import { createMachine, assign, fromPromise } from 'xstate';

export type Posts = {
  title: string
}[];

type RedditEvent = {
  type: 'SELECT';
  name: string
};

type RedditContext = {
  subreddit: null | string;
  posts: null | Posts;
}

function invokeFetchSubreddit(subreddit: RedditContext['subreddit']): Promise<Posts> {
  return fetch(`https://www.reddit.com/r/${subreddit}.json`)
          .then(res => res.json())
          .then(json => json.data.children.map((child: any) => child.data));
}

export const redditMachine = createMachine({
  // 类型定义
  types: {} as {
    context: RedditContext;
    events: RedditEvent;
  },
  id: 'reddit',
  /** 初始状态 -> 空闲 */
  initial: 'idle',
  context: {
    /** 已选子贴 */
    subreddit: null, // none selected
    /** 新闻信息 */
    posts: null,
  },
  states: {
    /** 空闲 -> 还没有子贴被选中 */
    idle: {},
    /** 已选 -> 某个子贴被选中 */
    selected: {
      // 子状态
      initial: 'loading',
      states: {
        loading: {
          invoke: {
            id: "fetch-subreddit",
            // fromPromise 处理异步 action
            // 通过 input 接受数据
            src: fromPromise(({ input }) => invokeFetchSubreddit(input.subreddit)),
            // 这里要传入 context 所需数据
            input: ({ context }) => ({
              subreddit: context.subreddit
            }),
            onDone: {
              target: 'loaded',
              actions: assign({
                // output 是上面 src 的返回结果
                posts: ({ event }) => event.output
              })
            },
            onError: "failed",
          }
        },
        // 因为是有限状态机，所以必须在 states 中显式声明出所有可能的状态值
        loaded: {},
        failed: {}
      }
    }
  },
  on: {
    SELECT: {
      // 过渡 transition 去子状态 '.selected' (注意 select 前面的点儿, 它代表一个关联目标 (relative-targets)
      target: '.selected',
      // 指派 assign event.name 给 context.subreddit
      actions: assign({
        subreddit: ({ event }) => event.name
      })
    }
  }
});
